﻿using System.Collections.Generic;
using System.IO;
using System.Xml;
using 热更验证;

namespace 数据验证
{
    class XmlLoader
    {
        private List<string> nodeList; //字段名列表
        private HashSet<string> setList; //重复ID列表
        private bool repeat; //判断是否重复字段
        private string xmlPath; //XML路径
        private string nodeX; //索引（key）字段名
        private int nodeLenght;//字段列表长度 -1

        /// <summary>
        /// 获取索引字段名
        /// </summary>
        public string NodeX
        {
            get { return nodeX; }
        }




        /// <summary>
        /// One 类型构造函数，只校准第一位字段是否重复
        /// </summary>
        public XmlLoader(string path)
        {
            try
            {
                using (XmlTextReader reader = new XmlTextReader(path))
                {
                    reader.WhitespaceHandling = WhitespaceHandling.None;
                    xmlPath = path;
                    nodeList = new List<string>();
                    setList = new HashSet<string>();
                    HashSet<string> set = new HashSet<string>();
                    string temp = "";
                    while (reader.Read())
                    {
                        if (reader.Depth == 2 & reader.NodeType == XmlNodeType.Element)
                        {
                            nodeList.Add(reader.Name);
                            temp = reader.ReadString();
                        }
                        if (reader.Depth == 1 & reader.NodeType == XmlNodeType.EndElement)
                        {
                            nodeList.TrimExcess();
                            break;
                        }
                    }
                    set.Add(temp);
                    nodeX = nodeList[0];
                    nodeLenght = nodeList.Count - 1;
                    while (reader.Read())
                    {
                        reader.ReadToFollowing(nodeX);
                        temp = reader.ReadString();
                        if (!set.Add(temp))
                        {
                            setList.Add(temp);
                        }
                    }
                }
                setList.TrimExcess();
            }
            catch (System.Exception)
            {
                throw;
;            }
            
        }

        /// <summary>
        /// Any 类型构造函数，可以校准任意字段是否包含重复值，
        /// </summary>
        /// <param name="path">文件地址</param>
        /// <param name="x">校准字段的索引位置，索引从 0 开始</param>
        public XmlLoader(string path,int x)
        {
            try
            {
                using (XmlTextReader reader = new XmlTextReader(path))
                {
                    reader.WhitespaceHandling = WhitespaceHandling.None;
                    nodeList = new List<string>();
                    setList = new HashSet<string>();
                    xmlPath = path;
                    HashSet<string> set = new HashSet<string>();
                    List<string> nodeValue = new List<string>();
                    while (reader.Read())
                    {
                        if (reader.Depth == 2 & reader.NodeType == XmlNodeType.Element)
                        {
                            nodeList.Add(reader.Name);
                            nodeValue.Add(reader.ReadString());
                        }
                        if (reader.Depth == 1 & reader.NodeType == XmlNodeType.EndElement)
                        {
                            nodeList.TrimExcess();
                            nodeValue.TrimExcess();
                            break;
                        }
                    }

                    nodeLenght = nodeList.Count - 1;
                    if (x > nodeLenght) x = nodeLenght;
                    if (x < 0) x = 0;

                    nodeX = nodeList[x];
                    set.Add(nodeValue[x]);
                    string temp = "";
                    while (reader.Read())
                    {
                        reader.ReadToFollowing(nodeX);
                        temp = reader.ReadString();
                        if (!set.Add(temp) & reader.EOF != true)
                        {
                            setList.Add(temp);
                        }
                    }
                }
                setList.TrimExcess();
            }
            catch (System.Exception ex)
            {
                throw;
            }

        }


        /// <summary>
        /// 检查索索引是否越界
        /// </summary>
        private int CheckIndex(int y)
        {
            if (y > nodeLenght) y = nodeLenght;
            if (y < 0) y = 0;
            if (nodeList[y] == nodeX) y ++;
            return y;
        }

        /// <summary>
        /// 获取索引（key）字段名
        /// </summary>
        public string GetKey()
        {
            return nodeX;
        }

        /// <summary>
        /// 检查是否存在重复 ID , true 为包含重复值
        /// </summary>
        public bool IsRepeate()
        {
            if (setList.Count == 0)
            {
                repeat = false;
            }
            else
            {
                repeat = true;
            }
            return repeat;
        }

        /// <summary>
        /// 获取重复 ID 列表
        /// </summary>
        public HashSet<string> GetRepeate()
        {
            return setList;
        }

        /// <summary>
        /// 获取所有字段名列表
        /// </summary>
        public List<string> GetNodeList()
        {
            return nodeList;
        }

        /// <summary>
        /// XML 一对一,第一列为索引
        /// </summary>
        /// <param name="y">列索引，索引从 1 开始</param>
        /// <returns>返回一个一对一的 HashK , key 为第一列ID</returns>
        public HashK<string,string> XtoY(int y)
        {
            y = CheckIndex(y);
            HashK<string, string> hashK = new HashK<string, string>();
            try
            {
                using (XmlTextReader textReader = new XmlTextReader(xmlPath))
                {
                    textReader.WhitespaceHandling = WhitespaceHandling.None;
                    string nodeY = nodeList[y];
                    while (textReader.Read())
                    {
                        textReader.ReadToFollowing(nodeX);
                        string tempX = textReader.ReadString();

                        textReader.ReadToFollowing(nodeY);
                        string tempY = textReader.ReadString();

                        if (!hashK.ContainsKey(tempX) & textReader.EOF != true)
                        {
                            hashK.Add(tempX, tempY);
                        }
                    }
                }
                return hashK;
            }
            catch (System.Exception ex)
            {
                throw;
            }

        }

        /// <summary>
        /// XML 一对一,任意位置索引，使用与构造函数一致的 key 作为索引
        /// </summary>
        /// <param name="y"> value 的索引</param>
        /// <returns>返回一个一对一的 HashK , key 为 Any 类型构造函数的 x 列 ID</returns>
        public HashK<string, string> AnyWhere(int y)
        {
            HashK<string, string> hashK = new HashK<string, string>();
            y = CheckIndex(y);
            try
            {
                using (XmlTextReader textReader = new XmlTextReader(xmlPath))
                {
                    textReader.WhitespaceHandling = WhitespaceHandling.None;
                    string nodeY = nodeList[y];
                    string tempX = "";
                    string tempY = "";
                    while (textReader.Read())
                    {
                        if (textReader.Depth == 2 & textReader.NodeType == XmlNodeType.Element)
                        {
                            if (textReader.Name == nodeX)
                            {
                                tempX = textReader.ReadString();
                            }
                            if (textReader.Name == nodeY)
                            {
                                tempY = textReader.ReadString();
                            }
                        }
                        if (textReader.Depth == 1 & textReader.NodeType == XmlNodeType.EndElement)
                        {
                            if (!hashK.ContainsKey(tempX))
                            {
                                hashK.Add(tempX, tempY);
                            }
                        }
                    }
                }
                return hashK;
            }
            catch (System.Exception ex)
            {
                throw;
            }

        }


        /// <summary>
        /// XML 一对一,任意位置索引，使用与构造函数不一致的 key 作为索引，重复列表会修改为新的重复列表
        /// </summary>
        /// <param name="x"> key 的索引</param>
        /// <param name="y"> value 的索引</param>
        /// <returns>返回一个一对一的 HashK , key 为指定 x 列 ID</returns>
        public HashK<string, string> AnyWhere(int x ,int y)
        {
            setList.Clear();
            HashK<string, string> hashK = new HashK<string, string>();
            HashSet<string> set = new HashSet<string>();
            try
            {
                using (XmlTextReader textReader = new XmlTextReader(xmlPath))
                {
                    textReader.WhitespaceHandling = WhitespaceHandling.None;
                    string nodeX = nodeList[x];
                    string nodeY = nodeList[y];
                    string tempX = "";
                    string tempY = "";
                    while (textReader.Read())
                    {
                        if (textReader.Depth == 2 & textReader.NodeType == XmlNodeType.Element)
                        {
                            if (textReader.Name == nodeX)
                            {
                                tempX = textReader.ReadString();
                                if (!set.Add(tempX))
                                {
                                    setList.Add(tempX);
                                }
                            }
                            if (textReader.Name == nodeY)
                            {
                                tempY = textReader.ReadString();
                            }
                        }

                        if (textReader.Depth == 1 & textReader.NodeType == XmlNodeType.EndElement)
                        {
                            if (!hashK.ContainsKey(tempX))
                            {
                                hashK.Add(tempX, tempY);
                            }
                        }
                    }
                }
                setList.TrimExcess();
                return hashK;
            }
            catch (System.Exception ex)
            {
                throw;
            }

        }


        /// <summary>
        /// XML 一对多，第一列为索引
        /// </summary>
        /// <param name="index">列索引数组</param>
        /// <returns>返回一个以第一列 ID 为 key 的哈希表，值为数组类型的 list，</returns>
        public HashK<string, List<string[]>> XtoNX(int[] index)
        {
            HashK<string, List<string[]>> hashK = new HashK<string, List<string[]>>();
            int length = index.Length;
            XmlTextReader reader;
            int n = 0;
            try
            {
                foreach (var y in index)
                {
                    if (n == 0)
                    {
                        using (reader = new XmlTextReader(xmlPath))
                        {
                            reader.WhitespaceHandling = WhitespaceHandling.None;
                            while (reader.Read())
                            {
                                reader.ReadToFollowing(nodeX);
                                string tempX = reader.ReadString(); //key

                                reader.ReadToFollowing(nodeList[y]);
                                string tempY = reader.ReadString(); //value

                                if (reader.EOF != true)
                                {
                                    if (!hashK.Contains(tempX)) //判断 key 是否没添加过
                                    {
                                        //新增一组 list + array 的数据组
                                        string[] array = new string[length];
                                        array[0] = tempY;
                                        hashK.Add(tempX, new List<string[]> { array });
                                    }
                                    else  //已经添加过 key ，添加新 array
                                    {
                                        List<string[]> list = hashK.GetTvalue(tempX);
                                        string[] array = new string[length];
                                        array[0] = tempY;
                                        list.Add(array);
                                    }
                                }
                            }
                        }
                    }
                    if (n > 0)
                    {
                        using (reader = new XmlTextReader(xmlPath))
                        {
                            reader.WhitespaceHandling = WhitespaceHandling.None;

                            Dictionary<string, int> dic = new Dictionary<string, int>(); //记录未完全遍历的 key 它的列表对应的下标

                            int s = 0; //记录 key 遍历列表的下标

                            string olderX = ""; //记录上一轮 key 的值

                            List<string[]> list = null; //获取 key 的数组列表

                            while (reader.Read())
                            {
                                reader.ReadToFollowing(nodeX);
                                string tempX = reader.ReadString(); //key

                                reader.ReadToFollowing(nodeList[y]);
                                string tempY = reader.ReadString(); //value

                                if (olderX == "") //*第一轮* 将记录旧值的字符串初始化为第一个 key 的值
                                {
                                    olderX = tempX;
                                    list = hashK.GetTvalue(tempX); //获取第一轮 key 的 list
                                }

                                if (olderX != tempX) //新 key 是否和老 key *不一致* （不一致则表示上一个 key 的 list 轮回已经结束）
                                {
                                    if (s != list.Count - 1) //判断上一轮的 key 对应的列表是否 *未被遍历* 完毕
                                    {
                                        if (dic.ContainsKey(olderX))//判断上一轮的 key 是否 *已经添加* 在未完全遍历的字典中
                                        {
                                            dic[olderX] = s;  //已经在字典中的 key ，将他的 list *下标更新*
                                        }
                                        else
                                        {
                                            dic.Add(olderX, s); //不在字典中的，*添加* key 和 list 下标
                                        }

                                    }

                                    s = 0; //结束上一个轮回，则 *初始化下标的值*

                                    if (dic.ContainsKey(tempX)) //判断新 key 是否包含在未完成遍历字典中
                                    {
                                        s = dic[tempX]; //已经在字典中的，获取上一次遍历的下标
                                    }
                                    list = hashK.GetTvalue(tempX); //获取当前 key 对应的 list
                                }

                                if (reader.EOF != true)
                                {
                                    //无论新和旧是否一致，都必须为当前轮回中的 list 对应的 索引字段数组取值
                                    list[s][n] = tempY; //获取当前轮回下标的数组第 n 个索引的字段的值
                                    olderX = tempX; //将当前 key 变成旧 key 
                                    s++; //下标+1
                                }

                            }
                        }
                    }
                    n++;
                }
                return hashK;
            }
            catch (System.Exception)
            {
                throw;
            }
        }
    }
}
